import axios from "axios";
import Qs from "qs"
import {config} from "@/config/index.js";

function create(baseUrl, requestInterceptor, responseInterceptor, responseError) {
    function requestError() {
        return Promise.reject(new Error('客户端请求异常'))
    }

    function makeFormData(info) {
        let formData = new FormData()
        let keys = Object.keys(info)
        for (let key of keys) {
            formData.append(key, info[key])
        }
        return formData
    }

    let baseConfig = {
        url: '',
        method: '',
        baseURL: baseUrl,
        headers: {},
        timeout: 3000,
        responseType: '',
        onUploadProgress: (event) => {
        },
        onDownloadProgress: (event) => {
        },
        paramsSerializer: function (params) {
            return Qs.stringify(params, {arrayFormat: 'brackets'})
        },
    }

    function paramForJson() {
        let instance = axios.create({
            ...baseConfig,
            method: 'get',
            responseType: 'json',
        })
        instance.interceptors.request.use(requestInterceptor, requestError)
        instance.interceptors.response.use(responseInterceptor, responseError)

        return async function (url, info, options = {}) {
            let res = await instance.request({
                url,
                params: info,
                ...options
            })
            return res.data
        }
    }

    function jsonForJson() {
        let instance = axios.create({
            ...baseConfig,
            method: 'post',
            headers: {
                'Content-Type': 'application/json'
            },
            responseType: 'json',
        })
        instance.interceptors.request.use(requestInterceptor, requestError)
        instance.interceptors.response.use(responseInterceptor, responseError)

        return async function (url, info, options = {}) {
            let res = await instance.request({
                url,
                data: info,
                ...options
            })
            return res.data
        }
    }

    function formDataForJson() {
        let instance = axios.create({
            ...baseConfig,
            method: 'post',
            headers: {
                'Content-Type': 'multipart/form-data'
            },
            responseType: 'json',
        })
        instance.interceptors.request.use(requestInterceptor, requestError)
        instance.interceptors.response.use(responseInterceptor, responseError)

        return async function (url, info, options = {}) {
            let res = await instance.request({
                url,
                data: info,
                ...options
            })
            return res.data
        }
    }

    function paramForBlob() {
        let instance = axios.create({
            ...baseConfig,
            method: 'get',
            responseType: 'blob',
        })
        instance.interceptors.request.use(requestInterceptor, requestError)
        instance.interceptors.response.use(responseInterceptor, responseError)

        return async function (url, info, options = {}) {
            let res = await instance.request({
                url,
                params: info,
                ...options
            })
            return res.data
        }
    }

    function jsonForBlob() {
        let instance = axios.create({
            ...baseConfig,
            method: 'post',
            headers: {
                'Content-Type': 'application/json'
            },
            responseType: 'blob'
        })
        instance.interceptors.request.use(requestInterceptor, requestError)
        instance.interceptors.response.use(responseInterceptor, responseError)

        return async function (url, info, options = {}) {
            let res = await instance.request({
                url,
                data: info,
                ...options
            })
            return res.data
        }
    }

    function formDataForBlob() {
        let instance = axios.create({
            ...baseConfig,
            method: 'post',
            headers: {
                'Content-Type': 'multipart/form-data'
            },
            responseType: 'blob',
        })
        instance.interceptors.request.use(requestInterceptor, requestError)
        instance.interceptors.response.use(responseInterceptor, responseError)

        return async function (url, info, options = {}) {
            let res = await instance.request({
                url,
                data: info,
                ...options
            })
            return res.data
        }
    }

    function paramForArrayBuffer() {
        let instance = axios.create({
            ...baseConfig,
            method: 'get',
            responseType: 'arraybuffer',
        })
        instance.interceptors.request.use(requestInterceptor, requestError)
        instance.interceptors.response.use(responseInterceptor, responseError)

        return async function (url, info, options = {}) {
            let res = await instance.request({
                url,
                params: info,
                ...options
            })
            return res.data
        }
    }

    function jsonForArrayBuffer() {
        let instance = axios.create({
            ...baseConfig,
            method: 'post',
            headers: {
                'Content-Type': 'application/json'
            },
            responseType: 'arraybuffer'
        })
        instance.interceptors.request.use(requestInterceptor, requestError)
        instance.interceptors.response.use(responseInterceptor, responseError)

        return async function (url, info, options = {}) {
            let res = await instance.request({
                url,
                data: info,
                ...options
            })
            return res.data
        }
    }

    function formDataForArrayBuffer() {
        let instance = axios.create({
            ...baseConfig,
            method: 'post',
            headers: {
                'Content-Type': 'multipart/form-data'
            },
            responseType: 'arraybuffer',
        })
        instance.interceptors.request.use(requestInterceptor, requestError)
        instance.interceptors.response.use(responseInterceptor, responseError)

        return async function (url, info, options = {}) {
            let res = await instance.request({
                url,
                data: info,
                ...options
            })
            return res.data
        }
    }

    async function paramForStream(url, info, onData, onEnd, options = {}) {
        url = baseConfig.baseURL + url
        url = new URL(url)
        url.search = Qs.stringify(info, {arrayFormat: 'brackets'})
        let response
        try {
            response = await fetch(url.href, {
                method: 'GET',
                headers: {
                    ...(baseConfig.headers),
                    ...(options.headers)
                },
            })
        } catch (error) {
            await responseError()
        }
        await responseInterceptor(response, responseError)

        let reader = response.body.getReader()

        while (true) {
            let result = await reader.read()
            if (result.done) {
                await onEnd()
                break
            }
            await onData(result.value)
        }
    }

    async function jsonForStream(url, info, onData, onEnd, options = {}) {
        url = baseConfig.baseURL + url
        let response
        try {
            response = await fetch(url, {
                method: 'POST',
                headers: {
                    ...(baseConfig.headers),
                    'Content-Type': 'application/json',
                    ...(options.headers)
                },
                body: Json.stringify(info)
            })
        } catch (error) {
            await responseError()
        }
        await responseInterceptor(response, responseError)

        let reader = response.body.getReader()

        while (true) {
            let result = await reader.read()
            if (result.done) {
                await onEnd()
                break
            }
            await onData(result.value)
        }
    }

    async function formDataForStream(url, info, onData, onEnd, options = {}) {
        url = baseConfig.baseURL + url
        let response
        try {
            response = await fetch(url, {
                method: 'POST',
                headers: {
                    ...(baseConfig.headers),
                    ...(options.headers)
                },
                body: makeFormData(info)
            })
        } catch (error) {
            await responseError()
        }

        await responseInterceptor(response, responseError)

        let reader = response.body.getReader()

        while (true) {
            let result = await reader.read()
            if (result.done) {
                await onEnd()
                break
            }
            await onData(result.value)
        }
    }

    return {
        paramForJson: paramForJson(),
        jsonForJson: jsonForJson(),
        formDataForJson: formDataForJson(),
        paramForBlob: paramForBlob(),
        jsonForBlob: jsonForBlob(),
        formDataForBlob: formDataForBlob(),
        paramForArrayBuffer: paramForArrayBuffer(),
        jsonForArrayBuffer: jsonForArrayBuffer(),
        formDataForArrayBuffer: formDataForArrayBuffer(),
        paramForStream,
        jsonForStream,
        formDataForStream
    }
}

let mainInstance = create(config.axiosMainInstanceBaseUrl, (config) => {
    config.headers.Authorization = `Behavior ${sessionStorage.getItem('token')}`
    return config
}, async (response, responseError) => {
    let data = response.data


    if (responseError) {
        if (response.status < 200 || response.status >= 300) {
            await responseError()
        }
    }

    if (response.data) {
        let status = data.status
        if (status !== 1) {
            throw new Error('数据不可用')
        }
    }
    return response
}, () => {
    return Promise.reject(new Error('服务端响应异常'))
})

export {mainInstance}